function Sniffer() {
    // toLowerCase
    const ua = navigator.userAgent.toLowerCase();
    const av = navigator.appVersion != undefined ? navigator.appVersion.toLowerCase() : '';
    const an = navigator.appName != undefined ? navigator.appName.toLowerCase() : '';
    const vd = navigator.vendor != undefined ? navigator.vendor.toLowerCase() : '';
    const pf = navigator.platform != undefined ? navigator.platform.toLowerCase() : '';
    // Platform - Mac : MacIntel, Windows: Win32/Win64, iPhone:iPhone, AndroidPhone: Linux

    const isWindowsPhone = /windows phone|iemobile|wpdesktop/.test(ua);
    const isAndroidPhone = !isWindowsPhone && /android.*mobile/.test(ua);
    const isAndroidTablet = !isWindowsPhone && !isAndroidPhone && /android/i.test(ua);
    const isWindowsTablet = !isWindowsPhone && !isAndroidPhone && ua.includes('windows') && ua.includes('touch');

    const isAndroid = isAndroidPhone || isAndroidTablet;

    const isIOS = !isWindowsPhone && /ip(hone|od|ad)/i.test(ua) && !window.MSStream;
    const isIPad = !isWindowsPhone && /ipad/i.test(ua) && isIOS;
    const isIPadPro = isIPad && window.screen.width + window.screen.height > 2000; // better solution?

    // window screen: iPhone 6/7/8->375|667,  iPhone 6/7/8 Plus->414|736, iPhone X->375|812

    const isTablet = isAndroidTablet || isIPad;
    const isPhone = isAndroidPhone || (isIOS && !isIPad) || isWindowsPhone;
    const isIPhone = isIOS && isPhone;
    const isTouch = isPhone || isTablet;
    const isFirefox = ua.includes('firefox');
    const isSafari = !!ua.match(/version\/[\d\.]+.*safari/);
    const isOpera = ua.includes('opr');
    const isIE11 = ua.includes('trident') && /v([\w\:\s*\d.]+)11/.test(ua);
    const isEdge = ua.includes('edge');
    const isIE = av.includes('msie') || ua.includes('trident') || isIE11 || isEdge;
    const isLegacyIE = isIE && !isEdge && !isIE11;
    const isChrome =
        window.chrome !== null && window.chrome !== undefined && /google inc/.test(vd) && !isOpera && !isEdge;
    const isTwitter = isPhone && /t.co/.test(document.referrer);
    const isFacebook = isPhone && /fban|facebook|fbios|fbid/.test(ua);
    const isInstagram = isPhone && /instagram/.test(ua);
    const isSnapchat = isPhone && /snapchat/.test(ua);
    const isWeChat = isPhone && /micromessenger/.test(ua);
    const isAndroidWeChat = isAndroid && isWeChat;
    const isIOSWeChat = isIOS && isWeChat;
    const isSocialApp = isTwitter || isFacebook || isInstagram || isSnapchat || isWeChat;
    const isRealPhone = isPhone && !/mac|win/.test(pf);

    // Languages
    const isEn = (navigator.language || navigator.userLanguage).includes('en');
    const isZh = (navigator.language || navigator.userLanguage).includes('zh');

    // Canvas
    const hasCanvas = !!window.CanvasRenderingContext2D;

    // WebGL
    let hasWebGL;
    let hasWebGL2;
    if (hasCanvas) {
        hasWebGL = webgl();
        hasWebGL2 = webgl2();
    } else {
        hasWebGL = false;
        hasWebGL2 = false;
    }

    // Cookie
    let isCookieEnabled = navigator.cookieEnabled ? true : false;
    if (typeof navigator.cookieEnabled == 'undefined' && !isCookieEnabled) {
        document.cookie = 'testcookie';
        isCookieEnabled = document.cookie.includes('testcookie') ? true : false;
    }

    // Worker
    const hasWorker = !!window.Worker;

    // alert("isInstagram:"+isInstagram);
    // const debug = document.createElement('div');
    // debug.style.position = 'absolute';
    // debug.style.zIndex = 899;
    // document.body.appendChild( debug );
    // debug.innerHTML = "isTwitter: " + isTwitter + ", isFacebook: " + isFacebook;
    // alert( pf +" : "+ isRealPhone);

    this.data = versionize(
        {
            isAndroid,
            isAndroidPhone,
            isAndroidTablet,
            isWindowsPhone,
            isWindowsTablet,
            isIOS,
            isIPhone,
            isIPad,
            isIPadPro,
            isTouch,
            isEdge,
            isIE,
            isIE11,
            isLegacyIE, // IE 7/8/9/10
            isPhone,
            isTablet,
            isFirefox,
            isSafari,
            isOpera,
            isChrome,
            isDesktop: !isPhone && !isTablet,
            isDevice: isPhone || isTablet,
            isTwitter,
            isFacebook,
            isInstagram,
            isSnapchat,
            isWeChat,
            isAndroidWeChat,
            isIOSWeChat,
            isSocialApp,
            isRealPhone,
            isEn,
            isZh,
            isCookieEnabled,
            hasCanvas,
            hasWebGL,
            hasWebGL2,
            hasWorker,
        },
        ua,
        av,
        an
    );

    this.cssify = function (el) {
        const snifferStyle = {
            isMac: 'is-mac',
            isWin: 'is-win',
            isAndroid: 'is-android',
            isAndroidPhone: 'is-android-phone',
            isAndroidTablet: 'is-android-tablet',
            isWindowsPhone: 'is-windows-phone',
            isWindowsTablet: 'is-windows-tablet',
            isIOS: 'is-ios',
            isIPhone: 'is-iphone',
            isIPad: 'is-ipad',
            isIPadPro: 'is-ipad-pro',
            isTouch: 'is-touch',
            isEdge: 'is-edge',
            isIE: 'is-ie',
            isIE11: 'is-ie11',
            isLegacyIE: 'is-legacy-ie',
            isPhone: 'is-phone',
            isTablet: 'is-tablet',
            isFirefox: 'is-firefox',
            isSafari: 'is-safari',
            isOpera: 'is-opera',
            isChrome: 'is-chrome',
            isDesktop: 'is-desktop',
            isDevice: 'is-device',
            isTwitter: 'is-twitter',
            isFacebook: 'is-facebook',
            isInstagram: 'is-instagram',
            isSnapchat: 'is-snapchat',
            isWeChat: 'is-wechat',
            isAndroidWeChat: 'is-android-wechat',
            isIOSWeChat: 'is-ios-wechat',
            isSocialApp: 'is-social-app',
            isRealPhone: 'is-real-phone',
        };

        for (const key in this.data) {
            if (key != 'system' && key != 'browser' && this.data[key] && snifferStyle[key] != undefined)
                addClass(el, snifferStyle[key]);
        }

        // Add language attributes.
        if (isEn) {
            el.setAttribute('lang', 'en');
        } else if (isZh) {
            el.setAttribute('lang', 'zh');
        }

        // don't use dashify for 'hash' minification reason
        // for (let key in this.data) {
        //  if(key != "system" && key != "browser" && this.data[key]) addClass(el, dashify(key));
        // }
    };
}

function versionize(data, ua, av, an) {
    let browser;
    let browserVersion;
    let os;
    let osVersion;
    let v;
    let i;

    if (data.isOpera) {
        v = ua.indexOf('opr');
        browser = 'Opera';
        browserVersion = ua.substring(v + 4);
    } else if (data.isEdge) {
        v = ua.indexOf('edge');
        browser = 'Edge';
        browserVersion = ua.substring(v + 5);
    } else if (data.isIE && !data.isIE11) {
        v = ua.indexOf('msie');
        browser = 'IE';
        browserVersion = ua.substring(v + 5);
    } else if (data.isIE11) {
        browser = 'IE11';
        browserVersion = ua.substring(ua.indexOf('rv:') + 3);
    } else if (data.isChrome) {
        v = ua.indexOf('chrome');
        browser = 'Chrome';
        browserVersion = ua.substring(v + 7);
    } else if (data.isSafari) {
        v = ua.indexOf('safari');
        browser = 'Safari';
        browserVersion = ua.substring(v + 7);
        if ((v = ua.indexOf('version')) != -1) {
            browserVersion = ua.substring(v + 8);
        }
    } else if (data.isFirefox) {
        v = ua.indexOf('firefox');
        browser = 'Firefox';
        browserVersion = ua.substring(v + 8);
    } else {
        browser = 'Unknown';
        browserVersion = 'Unknown';
    }

    // trim the browserVersion string
    if ((i = browserVersion.indexOf(';')) != -1) browserVersion = browserVersion.substring(0, i);
    if ((i = browserVersion.indexOf(' ')) != -1) browserVersion = browserVersion.substring(0, i);
    if ((i = browserVersion.indexOf(')')) != -1) browserVersion = browserVersion.substring(0, i);

    // System
    if (/windows/.test(ua) && !data.isPhone) {
        os = 'Win';
        v = /nt ([\.\_\d]+)/.exec(ua);
        osVersion = v ? v[1] : 'Unknown';

        // Windows NT 10  10.0*
        // Windows NT 8.1 6.3*
        // Windows NT 8   6.2
        // Windows NT 7   6.1
        // Windows NT Vista   6.0
        // Windows NT XP  5.1
    } else if (/mac os/.test(ua) && data.isDesktop) {
        os = 'Mac';
        v = /mac os x (10[\.\_\d]+)/.exec(ua);
        osVersion = v ? v[1] : 'Unknown';
    } else if (/android/.test(ua)) {
        os = 'Android';
        v = /android ([\.\_\d]+)/.exec(ua);
        osVersion = v ? v[1] : 'Unknown';
    } else if (/(iphone|ipad|ipod)/.test(ua)) {
        os = 'iOS';
        v = /os (\d+)_(\d+)_?(\d+)?/.exec(av);
        osVersion = v ? `${v[1]}.${v[2]}.${v[3] | 0}` : 'Unknown';
    } else if (/(linux|x11)/.test(ua)) {
        os = 'Linux|Unix';
        osVersion = 'Unknown';
    } else {
        os = 'Unknown';
        osVersion = 'Unknown';
    }

    // format the osVersion string
    osVersion = osVersion.replace(/_/gi, '.');

    data.isMac = os == 'Mac';
    data.isWin = os == 'Win';

    data.system = {
        name: os,
        version: osVersion,
    };

    data.browser = {
        name: browser,
        version: browserVersion,
    };

    return data;
}

function webgl() {
    try {
        const canvas = document.createElement('canvas');
        return !!(
            window.WebGLRenderingContext &&
            (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
        );
    } catch (e) {
        return false;
    }
}

function webgl2() {
    try {
        const canvas = document.createElement('canvas');
        return !!(canvas.getContext('webgl2') || canvas.getContext('experimental-webgl2'));
    } catch (e) {
        return false;
    }
}

// function dashify(str) {
//  return str
//    .replace(/([a-z])([A-Z])/g, '$1-$2')
//    .replace(/[ \t\W]/g, '-')
//    .replace(/^-+|-+$/g, '')
//    .toLowerCase();
// };

function addClass(el, className) {
    if (el.addClass) el.addClass(className);
    else if (el.classList) el.classList.add(className);
    else el.className += ` ${className}`;
}

export default Sniffer;
